package com.shop.wk.filter.global;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.shop.wk.common.constant.HttpCode;
import com.shop.wk.common.dto.ResponseResult;
import com.shop.wk.service.AuthServiceDubbo;
import com.shop.wk.service.FilterService;
import com.shop.wk.utils.RequestUtil;
import java.nio.charset.StandardCharsets;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * @author 日月星辰
 * @date 2020/12/26 19:10
 * @description Authentication Check Filter
 */
@Slf4j
@Component
public class AuthenticationFilter implements GlobalFilter {

  public static final String BEARER_TYPE = "Bearer";

  @DubboReference(version = "1.0.0")
  private AuthServiceDubbo authServiceDubbo;

  @Value("${checkSign}")
  private Boolean checkSign;
  @Autowired
  private FilterService filterService;

  @Override
  public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    if (!checkSign) {
      if (log.isDebugEnabled()) {
        log.debug("Current application check sign is Disable.");
      }
      return chain.filter(exchange);
    }

    ServerHttpRequest request = exchange.getRequest();
    //黑名单 从redis中获取
    if (filterService.isBlackList(RequestUtil.getIpAddress(request))) {
      JSONObject reslut = new JSONObject();
      reslut.put("timestamp",System.currentTimeMillis());
      reslut.put("code", HttpCode.FAIL);
      reslut.put("message", "黑名单IP，禁止访问");
      return writeJsonResponse(reslut, exchange.getResponse());
    }

    //白名单request.getPath()  从redis中获取
    if (filterService.uriIsWihteList(request.getPath().value())) {
      return chain.filter(exchange);
    } else {
      System.out.println(request.getPath().value());
    }

    //检查token
    String token = getToken(request);
    if (token != null) {
      ResponseResult result = authServiceDubbo.checkToken(token);
      if (result.getCode() == 0 && ((int) result.getData() - 60) > 0) {
        log.info(result.toString());
        return chain.filter(exchange);
      }
    }
    log.warn("令牌无效{}", token);

    //判断是否是刷新token
    if (HttpMethod.POST.equals(request.getMethod())) {
      String refreshToken = getRefreshToken(request);
      if (refreshToken != null) {

      }
    }

    //响应无效令牌
    JSONObject reslut = new JSONObject();
    reslut.put("timestamp",System.currentTimeMillis());
    reslut.put("code", HttpCode.FAIL);
    reslut.put("message", "无效的token");
    return writeJsonResponse(reslut, exchange.getResponse());
  }

  private String getToken(ServerHttpRequest request) {
    String auth = request.getHeaders().getFirst("Authorization");
    if (StrUtil.isNotEmpty(auth)) {
      if (auth.indexOf(String.format("%s ", BEARER_TYPE)) != -1) {
        return auth.substring(7);//token=Bearer aaaaaaaaa  --> aaaaaaaaa
      }
    }
    auth = request.getQueryParams().getFirst("token");
    if (StrUtil.isNotBlank(auth)) {
      return auth;
    }
    return null;
  }

  private String getRefreshToken(ServerHttpRequest request) {
    String refreshToken = request.getHeaders().getFirst("refresh_token");
    if (StrUtil.isNotBlank(refreshToken)) {
      return refreshToken;
    }
    return request.getQueryParams().getFirst("refresh_token");
  }

  private Mono<Void> writeJsonResponse(JSONObject reslut, ServerHttpResponse response) {
    response.setStatusCode(HttpStatus.OK);
    response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
    DataBuffer buffer = response.bufferFactory().wrap(reslut.toString().getBytes(StandardCharsets.UTF_8));
    return response.writeWith(Mono.just(buffer));
  }
}
